import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

# 设置图像显示的字体样式
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题


# （1）由于每个csv中大概都有100多万条数据，我们采取分数据块读取
# 读取文件数据
def read_actionData(filePath, size=10000):
    """
    filePath ： 文件路径
    size ： 读取的数据行数
    """
    # 使用迭代器的方式读取数据
    """
    filePath：CSV文件路径
    header：指定第0行为列名
    iterator：设置为迭代器模式，分批次读取数据
    """
    df = pd.read_csv(filePath, header=0, iterator=True)
    # 保存数据块的列表
    chunks = []
    # 循环起始值，启动循环并决定循环是否继续执行
    loop = True
    # 循环读取数据
    while loop:
        try:
            # 从df中读取数据，行数默认为10000行，只保留5列数据
            chunk = df.get_chunk(size)[["user_id", "sku_id", "type",
                                        "time", 'cate']]
            chunks.append(chunk)  # 将读取的数据块添加到空列表chunk中
        except StopIteration:  # 捕获异常
            loop = False  # 出现异常结束循环
            print("Iteration is stopped")  # 输出提示信息
    """
    pd.concat()：用于拼接数据的函数
    chunks：循环中收集得到的数据块
    ignore_index=True：忽略原始每个小数据块的索引，拼接后重新生成一个连续的索引
    """
    df_ac = pd.concat(chunks, ignore_index=True)  # 将多个数据块进行拼接
    return df_ac


df_ac = read_actionData('Data_Action_201602.csv')
# print(df_ac)

# 提取type=4的数据
"""
标记潜在用户：
    必须有购买行为；
    对一个商品购买和其他交互行为时间相差一个多余一天
1.浏览商品详情页；2.加入购物车；3.购物车删除；4.下
单；5.关注；6.点击；
"""
df_ac_type = df_ac[df_ac['type'] == 4]
# print(df_ac_type)

# 查看每类商品用户下单的占比
# 按商品类别分组，统计每个类别的数据条数
cate_count = df_ac_type.groupby('cate').size().reset_index(name='count')
# 计算每个商品类别的数量占总数据量的比例
cate_count['rate'] = cate_count['count'] / df_ac_type.shape[0]
# print(cate_count)
# 得到结果cate=4的占比最高

# 选取cate=4的数据
df_ac_cate = df_ac_type[df_ac_type['cate'] == 4]


# print(df_ac_cate)

# 计算每个用户的最后购买时间
def last_time(user):
    return user['time'].max()


# 按用户ID分组，对每个用户应用自定义函数liat_time进行处理
df_usr_buy_time = df_ac_cate.groupby(by='user_id').apply(last_time)
# print(df_usr_buy_time)

# 最早与该商品发生交互得到日期
df_ac_allcate = df_ac[df_ac['cate'] == 4]
# print(df_ac_allcate)
# 筛选用户行为
df_all_buy_ac = pd.merge(df_usr_buy_time.to_frame(), df_ac_allcate, left_on='user_id', right_on='user_id')


# 获取每个用户最开始的时间
def first_time(user):
    return user['time'].min()


df_usr_ac_firsttime = df_all_buy_ac.groupby(by='user_id').apply(first_time)
# print(df_usr_ac_firsttime)

# 计算时间差
# 计算时间差（保留user_id）
df = pd.merge(
    df_usr_buy_time.to_frame(name='buy_time').reset_index(),
    df_usr_ac_firsttime.to_frame(name='ac_time').reset_index(),
    on='user_id'
)

df["days"] = (pd.to_datetime(df['buy_time']) - pd.to_datetime(df['ac_time'])).dt.days
# print(df)

# 获取高潜用户
high_dive = df[df['days'] > 1]
# print(high_dive)

# 保存结果
# high_dive.to_csv('high_dive.csv',index=False)


# 筛选高潜用户静态数据
user_table = pd.read_csv('User_table.csv')

# 将两个时间进行合并high_dive和user_table
user_table_high = pd.merge(user_table,
                           high_dive,
                           on='user_id'
                           )
# print(user_table_high)

# 高潜用户的客户等级分布
# 统计客户等级数量
grade_counts = user_table_high['user_lv_cd'].value_counts()
# 提取客户等级名
labels = grade_counts.index.tolist()
# 提取各等级客户数量作为数据的大小
sizes = grade_counts.values.tolist()
# 绘制饼图
plt.figure(figsize=(8, 6), dpi=80)
plt.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True, startangle=140)
plt.axis('equal')
plt.title('高潜用户的客户等级分布')
# 保存图像
plt.savefig('高潜用户的客户等级分布.png')
# 显示图形
plt.show()

# 高潜用户的年龄对比
# 清除age不合理的值
user_table_high['age'] = user_table_high['age'].apply(lambda x: np.nan if x < 0 or x > 110 else x)
print(user_table_high['age'])
bins = [0, 20, 30, 40, 50, 100]
labels = ['0-20', '21-30', '31-40', '41-50', '50+']
user_table_high['age_group'] = pd.cut(user_table_high['age'], bins=bins, labels=labels)
age_counts = user_table_high['age_group'].value_counts().sort_index()

plt.figure(figsize=(10, 6))
age_counts.plot(kind='bar')
plt.title('高潜客户的年龄段对比')
plt.xlabel('年龄段')
plt.ylabel('用户数量')
plt.xticks(rotation=0)
plt.savefig('高潜用户的年龄对比.png')
#
# plt.show()

# print(high_dive.columns.tolist())

# # 高潜用户购买记录
# high_dive = pd.read_csv('high_dive.csv')
# high_user_ids = high_dive[['user_id']].copy()
# #
# # # 以user_id为关联键，匹配高潜用户在df_ac_cate中的购买记录
# #
# high_user_purchase = pd.merge(
#     df_ac_cate,         # 第四类商品的购买记录
#     high_user_ids,      # 高潜用户ID列表
#     on='user_id',       # 通过用户ID匹配
#     how='inner'         # 只保留两边都存在的记录（即高潜用户的购买记录）
# )
# print(high_user_purchase)
# # 1. 按商品ID（sku_id）统计高潜用户的购买数量
# sku_purchase_count = high_user_purchase.groupby('sku_id')['user_id'].count().reset_index(name='purchase_num')
# # 取购买量前10的商品
# top_sku = sku_purchase_count.sort_values('purchase_num', ascending=False).head(10)
#
# # 2. 绘制条形图
# plt.figure(figsize=(12, 6))
# plt.bar(top_sku['sku_id'].astype(str), top_sku['purchase_num'], color='lightgreen')
# plt.title('高潜用户对第四类商品的购买数量（Top10）')
# plt.xlabel('商品ID（sku_id）')
# plt.ylabel('购买数量')
# plt.xticks(rotation=45)  # 旋转x轴标签，避免重叠
# plt.grid(axis='y', linestyle='--', alpha=0.6)
# plt.tight_layout()  # 调整布局
# plt.savefig('高潜用户购买记录.png')
# plt.show()


# # 周一到周日每天的购买数量
# # 1. 确保时间列转为datetime格式
# high_user_purchase['time'] = pd.to_datetime(high_user_purchase['time'])
#
# # 2. 提取星期信息（0=周一，6=周日，需映射为中文星期）
# high_user_purchase['weekday'] = high_user_purchase['time'].dt.weekday  # 获取0-6的数字
# weekday_map = {0: '周一', 1: '周二', 2: '周三', 3: '周四', 4: '周五', 5: '周六', 6: '周日'}
# high_user_purchase['weekday_name'] = high_user_purchase['weekday'].map(weekday_map)
#
# # 3. 按星期统计购买数量
# weekday_counts = high_user_purchase.groupby('weekday_name').size().reindex(['周一', '周二', '周三', '周四', '周五', '周六', '周日'])
#
# # 4. 绘制条形图
# plt.figure(figsize=(10, 6))
# weekday_counts.plot(kind='bar', color='salmon')
# plt.title('高潜用户周一至周日购买数量分布')
# plt.xlabel('星期')
# plt.ylabel('购买数量')
# plt.xticks(rotation=0)
# plt.grid(axis='y', linestyle='--', alpha=0.7)
# plt.tight_layout()
# plt.savefig('高潜用户周一至周日购买数量分布.png')
# plt.show()


# 购买数量维度： 不同量段的占比
# 1.从高潜用户静态数据中提取购买数量user_table的buy_num
# user_table_high为高潜用户的静态数据表
# purchase_counts = user_table_high['buy_num']
#
# # 2. 定义购买量段
# bins = [0, 2, 5, float('inf')]
# labels = ['1-2件', '3-5件', '6件以上']
#
# # 3. 对购买数量进行分段
# purchase_bins = pd.cut(purchase_counts, bins=bins, labels=labels)
#
# # 4. 统计各量段的数量及占比
# bin_counts = purchase_bins.value_counts().sort_index()
# bin_rates = bin_counts / bin_counts.sum()
#
# # 5. 绘制饼图
# plt.figure(figsize=(8, 8))
# # 绘制饼图，显示占比并添加标签
# plt.pie(bin_rates, labels=labels, autopct='%1.1f%%', startangle=90, colors=['#ff9999','#66b3ff','#99ff99'])
# # 添加标题
# plt.title('高潜用户购买数量不同量段的占比')
# # 保证饼图为正圆形
# plt.axis('equal')
# plt.savefig('不同量的占比.png')
# # 显示图形
# plt.show()
